package asteroid

import (
	"gddgame.cc/galaxy/utils/def"
)

type SendHandler func(pipe *Pipe)

type Pipe struct {
	layer              *Layer
	data               interface{}
	nodes              []string
	origin             string
	target             string
	event              interface{}
	responseSerializer SerializerHandler
	responseData       bool
	response           *response
	cross              interface{}
	releaseList        []def.AutoSerializer

	send SendHandler
}

func newPipe(layer *Layer) *Pipe {
	p := &Pipe{
		layer: layer,
	}
	p.init()
	return p
}

func (p *Pipe) init() {
	p.target = ""
	p.origin = ""
	p.nodes = nil
	p.response = nil
	p.data = nil
	p.send = nil
	p.event = nil
	p.responseSerializer = nil
	p.responseData = false
	p.releaseList = nil

	p.cross = nil
}

func (p *Pipe) setSend(fn SendHandler) *Pipe {
	p.send = fn
	return p
}

// 跨区域访问：支持3种格式：
//               字符串：服务名称->所有网关的对应服务
//               		通过Router->Wans获取所有网关
//   					通过Router->Resolve分析字符串，得到对应节点列表，动态获取其中一个作为目标
//
//               不支持：网关名称->ip:port，无法得知对应目标服务
//
//   map[string]string：网关对应的节点关系或服务关系
//						通过Router->Wans分析key，得到对应网关列表
//   					通过Router->Resolve分析value，得到对应节点列表
// map[string][]string：网关对应的多节点关系
//						通过Router->Wans分析key，得到对应网关列表
// 设定后会忽略nodes相关发送目标设置
func (p *Pipe) Cross(info interface{}) *Pipe {
	p.cross = info
	return p
}

func (p *Pipe) Node(node string) *Pipe {
	if node != "" {
		p.nodes = []string{node}
	}
	return p
}

func (p *Pipe) Nodes(nodes []string) *Pipe {
	p.nodes = nodes
	return p
}

func (p *Pipe) ResponseSerialize(handler SerializerHandler) *Pipe {
	p.responseSerializer = handler
	return p
}

func (p *Pipe) ResponseData() *Pipe {
	p.responseData = true
	return p
}

func (p *Pipe) Callback(callback CallbackHandler) *Pipe {
	p.response = newResponse(callback, nil)
	return p
}
func (p *Pipe) CallbackTo(callback ToCallbackHandler) *Pipe {
	p.response = newResponse(nil, callback)
	return p
}

func (p *Pipe) Origin(id def.ID) *Pipe {
	return p.OriginId(id.ID())
}

func (p *Pipe) OriginId(id string) *Pipe {
	p.origin = id
	return p
}

func (p *Pipe) Target(id def.ID) *Pipe {
	return p.TargetId(id.ID())
}

func (p *Pipe) TargetId(id string) *Pipe {
	p.target = id
	return p
}
func (p *Pipe) Data(data interface{}) *Pipe {
	p.data = data
	return p
}
func (p *Pipe) List(data ...interface{}) *Pipe {
	p.data = data
	return p
}
func (p *Pipe) AutoRelease(serializer ...def.AutoSerializer) *Pipe {
	for _, re := range serializer {
		if re != nil {
			re.Alloc()
			p.releaseList = append(p.releaseList, re)
		}
	}
	return p
}

func (p *Pipe) Send(event interface{}) {
	p.event = event

	if p.response != nil {
		if p.responseSerializer != nil {
			p.response.getSerializer = p.responseSerializer
		} else if p.responseData {
			p.response.isData = true
		}
	}
	p.send(p)
	p.init()
	p.layer.pipePool.Put(p)
}
